package Default;

import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;

public class Routing {

	Manager manager;
	public Routing(Manager _manager)
	{
		manager=_manager;
	}
	
	public void setConnectionsNaive(/*Environment envi*/)
	{
		double [][]table = new double[manager.all_agents.size()][manager.all_agents.size()];
		// init the distance from any sensor to it's closest central
		Agent agent=null,agent2=null;
		double d;
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			//agent.connect.connectToId=-1;
			agent.connect.totalEnergyToTransmit=agent.calcConnection(manager.superNodes.get(0).position);
			//agent.connect.connectToPoint=manager.centers.get(0).position;
			agent.connect.connectTo=manager.superNodes.get(0);
			/*System.out.println(agent.connect.totalEnergyToTransmit);
			System.out.println(agent.connect.connectToId);
			System.out.println(agent.connect.connectToPoint);
			System.out.println(agent.position);*/
			for(int j=1;j<manager.superNodes.size();j++)
			{
				d=agent.calcConnection(manager.superNodes.get(j).position);
				if(agent.connect.totalEnergyToTransmit>d)
				{
					//agent.connect.connectToId=manager.centers.get(j).ID;
					agent.connect.totalEnergyToTransmit=d;
					//agent.connect.connectToPoint=manager.centers.get(j).position;
					agent.connect.connectTo=manager.superNodes.get(j);
				}
			}
		}
		//create table of connections
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			for(int j=0;j<manager.all_agents.size();j++)
			{
				table[i][j]=agent.calcConnection(manager.all_agents.get(j).position);
				//System.out.print(" "+table[i][j]);
			}
			//System.out.println();
		}
		manager.startSensorsFrame();
		try{
			Thread.sleep(50);
		}catch (Exception e)
		{
			e.printStackTrace();
		}
		boolean stop=true;
		do{
			stop=true;
			for(int i=0;i<manager.all_agents.size();i++)
			{
				agent=manager.all_agents.get(i);
				for(int j=0;j<manager.all_agents.size();j++)
				{
					//if(agent.connect.connectTo.ID>0)
					//	agent.connect.connectTo.connect.numOfMessege-=agent.connect.numOfMessege;
					agent2=manager.all_agents.get(j);
					if( (table[i][j]+agent2.connect.totalEnergyToTransmit) < agent.connect.totalEnergyToTransmit)
					{
						//agent.connect.connectToId=agent2.ID;
						//agent.connect.connectToPoint=agent2.position;
						agent.connect.totalEnergyToTransmit=table[i][j]+agent2.connect.totalEnergyToTransmit;
						agent.connect.connectTo=agent2;
					//	agent2.connect.numOfMessege+=agent.connect.numOfMessege;
						stop=false;
					}
				}
					
			}
			try{
				Thread.sleep(100);
			}catch (Exception e)
			{
				e.printStackTrace();
			}
			manager.frame.repaint();
		}while(!stop);
		
	}
	
	
	public void setConnectionsNaiveDynamic(/*Environment envi*/)
	{
		/**double [][]table = new double[manager.all_agents.size()][manager.all_agents.size()];*/
		
		ArrayList<double []> table=new ArrayList<double[]>();
		
		// init the distance from any sensor to it's closest central
		Agent agent=null,agent2=null;
		double d;
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			//agent.connect.connectToId=-1;
			agent.connect.totalEnergyToTransmit=agent.calcConnection(manager.superNodes.get(0).position);
			//agent.connect.connectToPoint=manager.centers.get(0).position;
			agent.connect.connectTo=manager.superNodes.get(0);
			/*System.out.println(agent.connect.totalEnergyToTransmit);
			System.out.println(agent.connect.connectToId);
			System.out.println(agent.connect.connectToPoint);
			System.out.println(agent.position);*/
			for(int j=1;j<manager.superNodes.size();j++)
			{
				d=agent.calcConnection(manager.superNodes.get(j).position);
				if(agent.connect.totalEnergyToTransmit>d)
				{
					//agent.connect.connectToId=manager.centers.get(j).ID;
					agent.connect.totalEnergyToTransmit=d;
					//agent.connect.connectToPoint=manager.centers.get(j).position;
					agent.connect.connectTo=manager.superNodes.get(j);
				}
			}
		}
		//create table of connections
		double []tmp;
		for(int i=0;i<manager.all_agents.size();i++)
		{
			tmp = new double[manager.all_agents.size()];
			System.out.println("hi");
			agent=manager.all_agents.get(i);
			for(int j=0;j<manager.all_agents.size();j++)
			{
				tmp[j]=agent.calcConnection(manager.all_agents.get(j).position);
				//System.out.print(" "+table[i][j]);
			}
			table.add(tmp);
			//System.out.println();
		}
		manager.startSensorsFrame();
		try{
			Thread.sleep(50);
		}catch (Exception e)
		{
			e.printStackTrace();
		}
		boolean stop=true;
		do{
			stop=true;
			for(int i=0;i<manager.all_agents.size();i++)
			{
				agent=manager.all_agents.get(i);
				for(int j=0;j<manager.all_agents.size();j++)
				{
					//if(agent.connect.connectTo.ID>0)
					//	agent.connect.connectTo.connect.numOfMessege-=agent.connect.numOfMessege;
					agent2=manager.all_agents.get(j);
					if( ((table.get(i))[j]+agent2.connect.totalEnergyToTransmit) < agent.connect.totalEnergyToTransmit)
					{
						//agent.connect.connectToId=agent2.ID;
						//agent.connect.connectToPoint=agent2.position;
						agent.connect.totalEnergyToTransmit=(table.get(i))[j]+agent2.connect.totalEnergyToTransmit;
						agent.connect.connectTo=agent2;
					//	agent2.connect.numOfMessege+=agent.connect.numOfMessege;
						stop=false;
					}
				}
					
			}
			try{
				Thread.sleep(100);
			}catch (Exception e)
			{
				e.printStackTrace();
			}
			manager.frame.repaint();
		}while(!stop);
		
	}
	
	public void setConnectionsDijkstra()
	{
		Agent agent=null,agent2;
		double min,tmp_min,d;
		int min_index_to=0,tmp_min_index=0,min_index=0;
		
		ArrayList<Agent> routing=new ArrayList<Agent>();
		manager.startSensorsFrame();
		for(int i=0;i<manager.superNodes.size();i++)//add to routing all the superNodes
		{
			agent=manager.superNodes.get(i);
			agent.childDepth=0;
			routing.add(agent);
		}
		for(int k=0;k<manager.all_agents.size();k++)
		{
			
			min=2000000000;
			for(int i=0;i<manager.all_agents.size();i++)
			{
				//tmp_min=2000000000;
				//System.out.println(tmp_min);
				agent=manager.all_agents.get(i);
				if(agent.childDepth==0)
				{
					
					tmp_min=2000000000;	
					for(int j=0;j<routing.size();j++)
					{
						agent2=routing.get(j);
						d=agent2.childDepth+agent.calcConnection(agent2.position);
						if(d<=tmp_min)
						{
							tmp_min=d;
							tmp_min_index=agent2.ID;
						}
					}
					if(tmp_min<min)
					{
						min=tmp_min;
						min_index_to=tmp_min_index;
						min_index=i;
					}
				}
			}
			System.out.print(min_index_to+" ");
			if(min_index_to>0 && agent!=null)
			{
				manager.all_agents.get(min_index).connect.connectTo=manager.all_agents.get(min_index_to-1);
				manager.all_agents.get(min_index).childDepth=manager.all_agents.get(min_index_to-1).childDepth+manager.all_agents.get(min_index).calcConnection(manager.all_agents.get(min_index_to-1).position);
			}
			if(min_index_to<0 && agent!=null)
			{
				manager.all_agents.get(min_index).connect.connectTo=manager.superNodes.get(min_index_to+1);
				manager.all_agents.get(min_index).childDepth=manager.all_agents.get((-1)*min_index_to-1).childDepth+manager.all_agents.get(min_index).calcConnection(manager.superNodes.get((-1)*min_index_to-1).position);
				System.out.println(manager.all_agents.get(min_index).childDepth+" "+manager.all_agents.get((-1)*min_index_to-1).childDepth+" "+(manager.all_agents.get(min_index).calcConnection(manager.all_agents.get((-1)*min_index_to-1).position)));
			}
			routing.add(manager.all_agents.get(min_index));
			manager.frame.repaint();
		}
	}
	
	
	public void setConnectionsClustering()
	{
		int j,cnt=0,id;
		int d= (int)Math.sqrt((Math.pow(Variables.sense_radius*2, 2))/2);
		System.out.println("d: "+d+" gridsizeY: "+Variables.gridSizeY);
		for(int i=d-1;i<Variables.gridSizeY;i+=d)
		{
			if(cnt%2==0)
				j=d;
			else
				j=d/2;
			for(;j<Variables.gridSizeX;j+=d)
			{
				id=findClosest(i, j,d);
				System.out.print(id+" ");
			}
			cnt++;
		}
	}
	public int findClosest(int y,int x,int d)
	{
		int [][]grid=Variables.grid;
		ArrayList<Integer> agents=new ArrayList<Integer>();
		for(int i=y-d;i<y+d;i++)
		{
			System.out.println("hi");
			if(i>=0 && i<Variables.gridSizeY)//else- out of bounds
			{
				for(int j=x-d;j<x+d;j++)
				{
					if(j>=0 && j<Variables.gridSizeX)
					{
						if(grid[i][j]!=0)
							agents.add(grid[i][j]);
					}
				}
			}
		}
		double min;
		int min_index;
		Point p=new Point(x,y);
		if(agents.isEmpty())
		{
			min_index=agents.get(0);
			min=manager.all_agents.get(agents.get(0)-1).calcConnection(p);
			for(int i=1;i<agents.size();i++)
			{
				if(manager.all_agents.get(agents.get(i)-1).calcConnection(p)<min)
				{
					min=manager.all_agents.get(agents.get(i)-1).calcConnection(p);
					min_index=agents.get(i);
				}
			}
			return min_index;
		}
		else
			return 0;
	}
	
	public void setChildren()
	{
		Agent agent,agent2;
		int id;
		boolean stop=true;
		//ArrayList<Integer> agentList=new ArrayList<Integer>();
		
		//for any sensor-add its ID to the parent
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			id=agent.ID;
			agent2=agent.connect.connectTo;
			agent2.connect.agentsConnectToMe.add(id);
		}
		//System.out.println(manager.all_agents.get(0).connect.agentsConnectToMe.size());
		
		
		//set the initial depth
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			if(agent.connect.agentsConnectToMe.isEmpty())
				agent.childDepth=0;
			else
				agent.childDepth=-1;
		}
		int j=0;
		//set the depth for any sensor
		try{
			do{
				stop=true;
				for(int i=0;i<manager.all_agents.size();i++)
				{
					
					agent=manager.all_agents.get(i);
					//if(agent.anotherField==-1)
					//	stop=false;
					if(agent.childDepth==j-1)
						agent.myColor=Color.green;
					if(agent.childDepth==j)
					{
						stop=false;
						agent.myColor=Color.red;
						agent2=agent.connect.connectTo;
						agent2.childDepth=j+1;
						/*
						 * need to pass all my children
						 */
						if(!agent2.connect.allAgentUnderMe.contains(agent.ID))
							agent2.connect.allAgentUnderMe.add(agent.ID);
						for(int k=0;k<agent.connect.allAgentUnderMe.size();k++)
						{
							if(!agent2.connect.allAgentUnderMe.contains(agent.connect.allAgentUnderMe.get(k)))
								agent2.connect.allAgentUnderMe.add(agent.connect.allAgentUnderMe.get(k));
							
						}
					}
					
				}
				manager.frame.repaint();
				Thread.sleep(10);
				j++;
			}while(!stop);
			
			/**
			 * to view all the sensors under any sensor
			for(int i=0;i<manager.all_agents.size();i++)
			{
				
				agent=manager.all_agents.get(i);
				//if(agent.anotherField==-1)
				//	stop=false;
				for(int k=0;k<manager.all_agents.size();k++)
				{
					agent2=manager.all_agents.get(k);
					if(agent.connect.allAgentUnderMe.contains(agent2.ID))
						agent2.myColor=Color.red;
					else
						agent2.myColor=Color.green;
					
				}
				agent.myColor=Color.black;
				manager.frame.repaint();
				Thread.sleep(100);
			}*/
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("depth: "+manager.superNodes.get(0).childDepth);
	}
	
	
	
	public void clearChildren()
	{
		Agent agent;
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			agent.connect.agentsConnectToMe.clear();
			agent.connect.allAgentUnderMe.clear();
		}
	}
	public boolean reConnectionsNaive(/*Environment envi*/)
	{
		double [][]table = new double[manager.all_agents.size()][manager.all_agents.size()];
		Agent agent=null,agent2=null;
		double d;
		boolean notLegalRouting=true;
		// init the routing from all the working sensors to closest central
		for(int i=0;i<manager.all_agents.size();i++)
		{
			
			agent=manager.all_agents.get(i);
			if(agent.battery<Variables.battery_Size)
			{
				//connect all the working sensors to the closest superNode
				agent.connect.totalEnergyToTransmit=agent.calcConnection(manager.superNodes.get(0).position);
				agent.connect.connectTo=manager.superNodes.get(0);
				for(int j=1;j<manager.superNodes.size();j++)
				{
					d=agent.calcConnection(manager.superNodes.get(j).position);
					if(agent.connect.totalEnergyToTransmit>d /*&& Math.sqrt(d)<=Variables.sense_radius*2*/)
					{
						agent.connect.totalEnergyToTransmit=d;
						agent.connect.connectTo=manager.superNodes.get(j);
					}
				}
				if(calcDistance(agent.position,agent.connect.connectTo.position )<=Variables.sense_radius*2)
					notLegalRouting=false;
			}
			
		}
		
		//create table of connections
		for(int i=0;i<manager.all_agents.size();i++)
		{
			agent=manager.all_agents.get(i);
			if(agent.battery<Variables.battery_Size)
			{
				for(int j=0;j<manager.all_agents.size();j++)
				{
					table[i][j]=agent.calcConnection(manager.all_agents.get(j).position);
					//System.out.print(" "+table[i][j]);
				}
			}
		}
		manager.frame.repaint();
		try{
			Thread.sleep(5);
		}catch (Exception e)
		{
			e.printStackTrace();
		}
		boolean stop=true;
		//connect any working sensor to better sensor routing
		do{
			stop=true;
			for(int i=0;i<manager.all_agents.size();i++)
			{
				agent=manager.all_agents.get(i);
				if(agent.battery<Variables.battery_Size)
				{
					
					for(int j=0;j<manager.all_agents.size();j++)
					{
						//if(agent.connect.connectTo.ID>0)
						//	agent.connect.connectTo.connect.numOfMessege-=agent.connect.numOfMessege;
						
						
						agent2=manager.all_agents.get(j);
						//connect only to working sensors
						if(agent2.battery<Variables.battery_Size)
						{
							if( (table[i][j]+agent2.connect.totalEnergyToTransmit) < agent.connect.totalEnergyToTransmit /*&& Math.sqrt(table[i][j])<=Variables.sense_radius*2*/)
							{
								//agent.connect.connectToId=agent2.ID;
								//agent.connect.connectToPoint=agent2.position;
								agent.connect.totalEnergyToTransmit=table[i][j]+agent2.connect.totalEnergyToTransmit;
								agent.connect.connectTo=agent2;
							//	agent2.connect.numOfMessege+=agent.connect.numOfMessege;
								stop=false;
							}
						}
					}
				}
					
			}
			try{
				Thread.sleep(1);
			}catch (Exception e)
			{
				e.printStackTrace();
			}
			manager.frame.repaint();
		}while(!stop);
		return notLegalRouting;
	}
	
	public double calcDistance(Point p1,Point p2)
	{
		double x=Math.abs(p1.x-p2.x);
		double y=Math.abs(p1.y-p2.y);
		double d=Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
		return d;
	}
}
